package com.zyfdroid.mindnote2.utils;

import android.content.Context;
import android.provider.ContactsContract;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class DocumentManager {

    private static File documentRootDir = null;
    private static File documentActiveDir = null;
    private static File documentDoneDir = null;

    public static SimpleDateFormat dateFormat = null;

    public static void InitDocumentDir(Context ctx){
        documentRootDir = new File(ctx.getFilesDir(),"docs2");
        if(!documentRootDir.exists()){
            documentRootDir.mkdirs();
        }
        documentActiveDir = new File(documentRootDir,"active2");
        documentDoneDir = new File(documentRootDir,"done2");
        if(!documentDoneDir.exists()){
            documentDoneDir.mkdirs();
        }
        if(!documentActiveDir.exists()){
            documentActiveDir.mkdirs();
        }
        dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
    }

    public static List<DocumentInfo> listDocuments(){
        return listDocuments(false);
    }

    public static List<DocumentInfo> listDocuments(boolean listDone) {
        File rootDir = listDone ? documentDoneDir : documentActiveDir;
        List<DocumentInfo> result = new ArrayList<>();
        for (File f :
                rootDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".txt"))) {
            DocumentInfo info = null;
            try {
                info = readDocumentInfo(f);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
            info.isDone = listDone;
            result.add(info);
        }
        Collections.sort(result,DocumentManager::documemtSortingMethod);
        return result;
    }

    private static int documemtSortingMethod(DocumentInfo d1,DocumentInfo d2){
        // 大意了，直接long相减然后转成int超过24天就会发生整数溢出导致排序错乱
        if(d2.lastModified.getTime() > d1.lastModified.getTime()){
            return 1;
        }else if(d2.lastModified.getTime() < d1.lastModified.getTime()){
            return -1;
        }
        return 0;
    }


    private static DocumentInfo readDocumentInfo(File f) throws IOException {
        try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f)))){
            String line = "";
            DocumentInfo documentInfo = new DocumentInfo();
            documentInfo.lastModified = new Date(f.lastModified());
            documentInfo.title = br.readLine();
            documentInfo.fileName = f.getName();
            return documentInfo;
        }catch (IOException ex){
            throw ex;
        }
    }

    public static DocumentInfo createNewDocument(){
        DocumentInfo documentInfo = new DocumentInfo();
        documentInfo.fileName = UUID.randomUUID().toString().replace("-","")+".txt";
        documentInfo.isDone = false;
        documentInfo.lastModified = new Date();
        documentInfo.title ="无标题 - " + dateFormat.format(documentInfo.lastModified);
        return documentInfo;
    }

    public static void moveDocumentToDone(DocumentInfo info){
        if(!info.isDone){
            File src = new File(documentActiveDir,info.fileName);
            File dst = new File(documentDoneDir,info.fileName);
            src.renameTo(dst);
        }

    }

    public static void deleteDocument(DocumentInfo info){
        File src = new File(info.isDone ? documentDoneDir : documentActiveDir,info.fileName);
        src.delete();
    }

    public static void moveDocumentToActive(DocumentInfo info){
        if(info.isDone){
            File src = new File(documentDoneDir,info.fileName);
            File dst = new File(documentActiveDir,info.fileName);
            src.renameTo(dst);
        }
    }

    public static DocumentContent getDocumentContent(DocumentInfo info) throws IOException {
        File src = new File(info.isDone ? documentDoneDir : documentActiveDir,info.fileName);
        DocumentContent content = new DocumentContent();
        content.filePath = src.getAbsolutePath();
        content.title = info.title;
        content.content = "";
        if(src.exists()){

            try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(src)))){
                String line = "";
                StringBuilder sb = new StringBuilder();
                br.readLine(); // discard the document title
                while ((line = br.readLine()) != null){
                    sb.append(line);
                    sb.append("\n");
                }
                if(sb.length() > 0){
                    sb.deleteCharAt(sb.length()-1);
                }
                content.content = sb.toString();
            }
        }
        return content;
    }

    public static void saveDocumentContent(DocumentContent content) throws IOException {
        File tmp = new File(content.filePath+".tmp");
        File src = new File(content.filePath);
        if(tmp.exists()){
            tmp.delete();
        }
        tmp.createNewFile();
        try(PrintStream ps = new PrintStream(tmp)){
            ps.println(content.title.replace('\r','_').replace('\n','_'));
            ps.println(content.content);
        }
        if(src.exists()){src.delete();}
        tmp.renameTo(src);
    }

    public static class DocumentInfo{
        public String fileName;
        public boolean isDone;
        public String title;
        public Date lastModified;
    }

    public static class DocumentContent{
        public String filePath;
        public String title;
        public String content;
    }

    public static String backupAll(Context ctx) throws IOException {
        File dir = new File(ctx.getCacheDir(),"share");
        if(!dir.exists()){dir.mkdirs();}
        File file = new File(dir,"mindnote2_backup.zip");
        if(file.exists()){file.delete();}
        try(ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(file), StandardCharsets.UTF_8)){
            zipDirectory(zipOutputStream,documentActiveDir);
            zipDirectory(zipOutputStream,documentDoneDir);
            zipOutputStream.finish();
        }
        return file.getAbsolutePath();
    }

    public static void restoreFile(Context ctx, InputStream fileSource) throws IOException {
        try(ZipInputStream zipInputStream = new ZipInputStream(fileSource)){
            ZipEntry zipEntry = null;
            while ((zipEntry = zipInputStream.getNextEntry()) != null){
                if(zipEntry.isDirectory()){
                    continue;
                }
                File ftemp = new File(documentRootDir,zipEntry.getName()+".tmp");
                File fdest = new File(documentRootDir,zipEntry.getName());
                try(FileOutputStream outputStream = new FileOutputStream(ftemp)){
                    byte[] data = new byte[2048];
                    int len;
                    while ((len = zipInputStream.read(data))> 0){
                        outputStream.write(data,0,len);
                    }
                }
                if(fdest.exists()){
                    fdest.delete();
                }
                ftemp.renameTo(fdest);
                fdest.setLastModified(zipEntry.getTime());
            }
        }
    }

    private static void zipDirectory(ZipOutputStream zos,File dir) throws IOException {
        String dirName = dir.getName();
        if(dirName.endsWith("/") || dirName.endsWith("\\")){
            dirName = dirName.substring(0,dirName.length()-1);
        }
        dirName += "/";

        for (File file : dir.listFiles()) {
            try(FileInputStream fis = new FileInputStream(file)){
                ZipEntry entry = new ZipEntry(dirName+file.getName());
                entry.setTime(file.lastModified());
                zos.putNextEntry(entry);
                byte[] data = new byte[2048];
                int len;
                while ((len = fis.read(data))> 0){
                    zos.write(data,0,len);
                }
                zos.closeEntry();
                zos.flush();
            }
        }

    }

}
